/**
 * 
 * Opened Touchable RIA Framework - A Web RIA Javascript Framework
 * 
 * Copyright (c) 2012
 * Dual licensed under the MIT or GPL v2 licenses.
 * 
 * @author  CuTe_CuBe
 * @version $Id: vml.js 5 2012-03-09 10:44:54Z CC.HGFeng@gmail.com $
 */

(function(){

var c = OTR.Chart, g = OTR.Graph;

/**
 * OTR.Chart.Flow
 * 流程图绘制工具
 * 
 * @class OTR.Chart.Flow
 * @constructor
 * @param object params
 * 参数列表
 * fontSize    字体大小
 * fontFamily  字体
 * lineWeight  连线宽度
 * lineColor   连线颜色
 * nodeBackground 节点背景颜色
 * nodeBorderColor 节点边框颜色
 * nodeBorderWeight 节点边框大小
 * branchBackground 分支节点背景
 * branchBorderColor 分支边框颜色
 * branchBorderWeight 分支边框大小
 * nodeMarginHor 节点垂直间距
 * nodeMarginVer 节点水平间距
 * nodeHeight 节点高度
 * style: 风格 linera.线性，节点以一列为排列， tree. 树状
 * padding: 边距
 * 
 */
c.Flow = function(params) {
    this._nodes    = [];
    this._nodeLink = {};
    this._cfgs  = c.Flow.defaults;
    
    OTR.apply(this._cfgs, params);
};

/**
 * 默认设置
 */
c.Flow.defaults = {
    fontSize: '12px',
    fontFamily: 'Arial',
    lineWeight: 1,
    lineColor: '#000000',
    nodeBackground: '#ffffff',
    nodeBorderColor: '#333333',
    nodeBorderWeight: 1,
    branchBackground: '#ffffff',
    branchBorderColor: '#333333',
    branchBorderWeight: 1,
    nodeMarginHor: 10,
    nodeMarginVer: 20,
    nodeHeight: 12,
    nodePadding: 12,
    style: 'linera',
    padding: 20
};

c.Flow.TYPE = {
    NODE: 1,
    BRANCH: 0,
    START: -1,
    END: -2
};

c.Flow.prototype = {
    
    /**
     * 标识是否已渲染
     * 
     * @type boolean
     */
    _isRendered: false,
    
    /**
     * 节点数量
     * 
     * @type int
     */
    _nodeCount: 0,
    
    /**
     * 分支数
     * 
     * @type int
     */
    _branchCount: 0,
    
    /**
     * 最大宽度
     * 
     * @type int
     */
    _maxLen: 0,

    /**
     * 添加流程步骤
     * 
     * @param OTR.Chart.Flow.Node node
     */
    addNode: function(node) {
        if (!node instanceof c.Flow.Node) {
            return ;
        }
        
        var l = this._nodes.length,
            fs = this._cfgs.fontSize,
            w = node.getText().length * parseInt(fs);
        
        this._maxLen = Math.max(w, this._maxLen);
        
        if (node.getType() == c.Flow.TYPE.BRANCH) {
            this._branchCount ++;
        }
        
        this._nodeCount++;
        this._nodes[l] = node;
        this._nodeLink[node.getId()] = l - 1;
    },
    
    /**
     * 获取流程步骤列表
     * 
     * return Array
     */
    getNodes: function() {
        return this._nodes;
    },
    
    /**
     * 图像添加到文档
     * 
     * @param container
     */
    renderTo: function(container) {
        if (!this._isRendered) {
            this.render();
        }
        
        this._canvas.renderTo(container);
    },
    
    /**
     * 渲染图像
     * 
     * @return void
     */
    render: function() {
        var nodes  = this._nodes,
            shapes = {},
            i = 0,
            l = nodes.length,
            bls = 0,
            ml  = this._maxLen;
        
        var cf = this._cfgs,
            padding = cf.padding,
            fs = parseInt(cf.fontSize),
            cw = ml + (2 * this._branchCount * cf.nodeMarginHor) + (2 * this._branchCount * cf.nodePadding) + 2 * padding,
            mv = cf.nodeMarginVer,
            mh = cf.nodeMarginHor,
            sh = cf.nodeHeight + cf.nodePadding * 2;
            nh = sh + mv * 2,
            ch = this._nodeCount * nh + 2 * padding;
        
        this._canvas = OTR.Graph.factory({
            width: cw,
            height: ch
        });
        
        for ( ; i < l; i++) {
            var node = nodes[i],
                type = node.getType(),
                text = node.getText(),
                nw   = text.length * fs + cf.nodePadding * 2;
            
            if (type == c.Flow.TYPE.BRANCH) {
                nw += 20;
            }
            
            var x    = (cw - nw) / 2,
                y    = padding + (i * nh) + mv,
                sp;

            if (type == c.Flow.TYPE.NODE) {
                sp = new g.Rect({
                    background: cf.nodeBackground,
                    borderWeight: cf.nodeBorderWeight,
                    borderColor: cf.nodeBorderColor,
                    x: x,
                    y: y,
                    width: nw,
                    height: sh,
                    borderRadius: 5
                });
            } else if (type == c.Flow.TYPE.BRANCH) {
                sp = new g.Polygon({
                    background: cf.branchBackground,
                    borderWeight: cf.branchBorderWeight,
                    borderColor: cf.branchBorderColor,
                    sideCount: 4, 
                    x: x,
                    y: y,
                    width: nw,
                    height: sh
                });
            } else {
                sp = new g.Cycle({
                    background: cf.nodeBackground,
                    borderWeight: cf.nodeBorderWeight,
                    borderColor: cf.nodeBorderColor,
                    x: (cw - sh)/2,
                    y: y,
                    width: sh,
                    height: sh
                });
            }
            
            shapes[node.getId()] = sp;
            
            this._canvas.drawShape(sp);
            
            if (type != c.Flow.TYPE.START && type !== c.Flow.TYPE.END) {
                this._canvas.drawShape(new g.Text({
                    text: text,
                    fontSize: fs,
                    x: x + cf.nodePadding + (type == c.Flow.TYPE.BRANCH ? 10 : 0),
                    y: y + cf.nodePadding
                }));
            }
            
            // 画线
            if (type != c.Flow.TYPE.END) {
                this._canvas.drawShape(new g.Line({
                    borderColor: cf.lineColor,
                    x: x + nw / 2,
                    y: y + sh,
                    dx: x + nw / 2,
                    dy: y + sh + 2 * cf.nodeMarginVer,
                    endArrow: 'Block'
                }));
                
                var nof = node.getWayFalse();
                
                if (undefined !== shapes[nof]) {
                    var sbk = shapes[nof],
                        bky = sbk.attr('y'),
                        bkh = sbk.attr('height'),
                        bkx = sbk.attr('x'),
                        bkw = sbk.attr('width'),
                        points = [];
                    
                    if (bls % 2 == 0) {
                        points.push({x: x + nw, y: y + sh / 2}),
                        points.push({x: x + nw + mh + ml / 2, y: y + sh / 2});
                        points.push({x: x + nw + mh + ml / 2, y: bky + bkh / 2});
                        points.push({x: bkx + bkw, y: bky + bkh / 2});
                    } else {
                        points.push({x: x, y: y + sh / 2}),
                        points.push({x: x - mh - ml / 2, y: y + sh / 2});
                        points.push({x: x - mh - ml / 2, y: bky + bkh / 2});
                        points.push({x: bkx, y: bky + bkh / 2});
                    }
                    
                    this._canvas.drawShape(new g.PolyLine({
                        borderColor: cf.lineColor,
                        points: points,
                        endArrow: 'Block'
                    }));
                    
                    bls++;
                }
            }
        }
        
        this._isRendered = true;
    }
};

})();